///************************************************************************
/// <copyrigth>2018-2019 Corporation.All Rights Reserved</copyrigth>
/// <author>tangyingzhong</author>
/// <contact>tangyz114987@outlook.com</contact>
/// <version>v1.0.0</version>
/// <describe>
/// It is duty for plugin's load,unload and maintain
///</describe>
/// <date>2020/7/26</date>
///***********************************************************************
#ifndef PLUGINMANAGER_H
#define PLUGINMANAGER_H

#include <map>
#include <mutex>
#include <set>
#include <thread>
#include "IPluginManager.h"

class PluginManager :public PluginBase<IPluginManager>
{
public:
	typedef ModuleLoader<IPlugin>* PluginLoader;
	typedef std::set<std::string > PluginTable;
	typedef std::map<std::string, PluginLoader> PluginContainer;
	typedef std::map<std::string, bool> PluginManualContainer;

public:
	// Construct the PluginManager
	PluginManager();
	
	// Detructe the PluginManager
	virtual ~PluginManager();
	
private:
	// Forbid the copy PluginManager
	PluginManager(const PluginManager& other){	};
	
	// Forbid the assigment of PluginManager
	PluginManager& operator=(const PluginManager& other){	return *this; };
	
public:
	// Start the manager
	virtual bool Start();

	// Stop the manager
	virtual bool Stop();

	// Set the thread pool
	virtual void SetPool(IThreadPool* pPool);

	// Start main service
	virtual bool StartMainService();

	// Get the plugin by name and version
	virtual IPlugin* GetPlugin(std::string strPluginName,
		int iMajorVersion,
		int iMinorVersion,
		int iModifyVersion);

	// Release the plugin
	virtual bool ReleasePlugin(IPlugin* pPlugin);

private:
	// Start sacnning task
	bool StartScanTask();

	// Stop scanning task
	void StopScanTask();

	// Start scanning available plugins
	void StartScanning();

	// Find plugins
	bool FindPlugins(String strScanPath, PluginTable& Container);

	// Searching plugins
	bool SearchPlugins(PluginTable& Container);

	// Load all available plugins
	bool LoadAllPlugins(PluginTable& Container);

	// Start all plugins here
	void StartAllPlugins();

	// Stop all plugins here
	void StopAllPlugins();

	// Unload all available plugins
	void UnloadAllPlugins();

	// Clear the container
	void ClearContainer();

private:
	// Start the plugin
	bool StartPlugin(String strPluginName);

	// Stop the plugin
	bool StopPlugin(String strPluginName);

	// Load plugin
	bool LoadPlugin(String strPluginFilePath);

	// Unload plugin
	bool UnloadPlugin(String strPluginName);

	// Get plugin name by path
	String GetPluginName(String strFilePath);

	// Unload plugin
	bool UnloadPlugin(PluginLoader& pLoader);

	// Start the plugin
	bool StartPlugin(IPlugin*& pPlugin);

	// Stop the plugin
	bool StopPlugin(IPlugin*& pPlugin);

	// Get main service
	bool GetMainService(IPlugin*& pPlugin);

private:
	// Add plugin
	bool AddPlugin(String strPluginName, PluginLoader& pLoader);

	// Remove plugin by id
	bool RemovePlugin(String strPluginName);

	// Remove plugin
	bool RemovePlugin(IPlugin*& pPlugin);

	// Get plugin
	bool GetPlugin(String strPluginName, PluginLoader& pLoader);

	// Is plugin existed
	bool IsPluginExisted(String strPluginName);

private:
	// Initialize the PluginManager
	void Initialize();
	
	// Destory the PluginManager
	void Destory();

	// Init the scan location
	void InitScanLocation();

	// Create module loader 
	bool CreateModuleLoader(PluginLoader& pLoader);

	// Destory module loader
	void DestoryModuleLoader(PluginLoader& pLoader);

private:
	// Get thread pool
	inline IThreadPool* GetThreadPool() const
	{
		return m_pPool;
	}

	// Set thread pool
	inline void SetThreadPool(IThreadPool* pPool)
	{
		m_pPool = pPool;
	}

	// Get sacn directory path
	inline String GetScanDirPath() const
	{
		return m_strScanDirPath;
	}

	// Set sacn directory path
	inline void SetScanDirPath(String strPath)
	{
		m_strScanDirPath = strPath;
	}

	// Get scan task id
	inline std::string GetScanTaskId() const
	{
		return m_strScanTaskId;
	}

	// Set scan task id
	inline void SetScanTaskId(std::string strId)
	{
		m_strScanTaskId = strId;
	}

	// Get scan task name
	inline std::string GetScanTaskName() const
	{
		return m_strScanTaskName;
	}

	// Set scan task id
	inline void SetScanTaskName(std::string strName)
	{
		m_strScanTaskName = strName;
	}

	// Get the disposed status
	inline bool GetDisposed() const
	{
		return m_bDisposed;
	}
	
	// Set the disposed status
	inline void SetDisposed(bool bDisposed)
	{
		m_bDisposed = bDisposed;
	}

private:
	// Thread pool
	IThreadPool* m_pPool;

	// Scan directory
	String m_strScanDirPath;

	// Request task Id
	std::string m_strScanTaskId;

	// Request task name
	std::string m_strScanTaskName;

	// Lock for the container
	std::mutex m_PluginLock;

	// Plugin container
	PluginContainer m_PluginContainer;

	// Disposed status
	Boolean m_bDisposed;
};
	
#endif // PLUGINMANAGER_H
